package com.katesoft.scale4j.rttp.client;

import com.katesoft.scale4j.rttp.internal.AppContext;

import java.io.Serializable;

/**
 * This class is created as helper class for distribution task executions.
 * <p/>
 * The problem that distributed frameworks, such as used in jvmcluster(hazelcast, quartz, spring batch) are able to work only with serializable objects
 * because
 * they are trying to transfer data through network or even persist internal state into database.
 * <p/>
 * It is clear that it is impossible and does not make any sense to serialize spring application context.
 * <p/>
 * So this interface should provide a way to access spring context in distributed env.
 *
 * @author kate2007
 */
public interface ISpringContextAccessor extends Serializable
{
    ISpringContextAccessor ACCESSOR = new SpringContextAccessor();

    /**
     * looking up bean by name.
     *
     * @param bean name of bean
     *
     * @return bean from application context.
     */
    Object getBean(String bean);

    /**
     * looking up bean by name and given class.
     *
     * @param bean  name of bean
     * @param clazz expected class
     *
     * @return bean from application context.
     */
    <T> T getBean(String bean,
                  Class<T> clazz);

    /**
     * Populate the given bean instance through applying after-instantiation callbacks and bean property post-processing (e.g. for annotation-driven
     * injection).
     *
     * @param bean object to run autowiring on
     *
     * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#autowireBean(Object)
     * @return passed bean
     */
    <T> T autowire(T bean);

    /** @author kate2007 */
    static class SpringContextAccessor implements ISpringContextAccessor
    {
        @Override
        public Object getBean(String bean)
        {
            return AppContext.getApplicationContext().getBean(bean);
        }

        @Override
        public <T> T getBean(String bean,
                             Class<T> clazz)
        {
            return AppContext.getApplicationContext().getBean(bean, clazz);
        }

        @Override
        public <T> T autowire(T bean)
        {
            AppContext.getApplicationContext().getAutowireCapableBeanFactory().autowireBean(bean);
            return bean;
        }
    }
}
